package poker;

/** KLASA Hand - REKA DANEGO GRACZA. */
public class Hand {
	
  /** TABLICA OBIEKTOW KLASY Card. */
  private Card[] cards;
  
  /** TABLICA WARTOSCI. */
  private int[] value;
  
  /** PIERWSZY KONSTRUKTOR KLASY Hand.
   * @param d - TALIA, Z KTOREJ ZOSTAJA POBRANE KARTY W AKTUALNYM ROZDANIU. */
  Hand(Deck d) {
    value = new int[6];
	cards = new Card[5];
	for (int x = 0; x  < 5; x++) {
      cards[x] = d.drawFromDeck();
	}
  }

  /** DRUGI KONSTRUKTOR KLASY Hand. */
  Hand (Card C0, Card C1, Card C2, Card C3, Card C4){
    value = new int[6];
    cards = new Card[5];
    cards[0]=C0;
    cards[1]=C1;
    cards[2]=C2;
    cards[3]=C3;
    cards[4]=C4;
  }
  
  /** METODA WYMIENIAJACA KARTY.
   * @param d - TALIA, Z KTOREJ ZOSTAJA POBRANE KARTY W AKTUALNYM ROZDANIU.
   * @param cardsToExchange - TABLICA KART DO WYMIANY */
  void exchange(Deck d, int[] cardsToExchange){
	    if(cardsToExchange[0]!=0){
	      for(int i=0;i<(cardsToExchange.length);i++){
		    cards[cardsToExchange[i]-1]=d.drawFromDeck();
		  }
		}
	  }

  /** METODA DRUKUJACA AKTUALNIE TRZYMANE KARTY. */
  void display() {
    for (int x = 0; x < 5; x++) { System.out.println("(" + (x + 1) + ")" + " " + cards[x]); }
	System.out.println();
  }

  /** METODA POROWNUJACA WARTOSCI RAK DWOCH GRACZY.
   * @param that - REKA Z KTORA POROWNUJEMY NASZA.
   * @return (1) - NASZA REKA JEST WIEKSZA, (-1) - NASZA REKA JEST MNIEJSZA, (0) - RECE SA ROWNE. */
  int compareTo(Hand that) {
	for(int x = 0; x < 6; x++){
	  if (this.value[x] > that.value[x]) { return 1; }
	  else if (this.value[x] < that.value[x]) { return -1; } 
	}
	return 0; 
  }

  /** METODA OCENIAJACA UKLAD KART W RECE. */
  void evaluate() {
	int[] ranks = new int[14];
	int[] orderedRanks = new int[5];
	boolean flush = true, straight = false;
	int index = 0, sameCards = 1, sameCards2 = 1, largeGroupRank = 0, smallGroupRank = 0, topStraightValue = 0;
	

	for (int x = 0;x < 14 ;x++) {
	  ranks[x] = 0;
	}

	/** INKREMENTACJA MIEJSC W TABLICY, ODPOWIADAJACYCH WARTOSCIOM KART. */
	for (int x=0 ;x < 5 ;x++) {
	  ranks[cards[x].getRank()]++;
	}

	/** SPRAWDZENIE, CZY JEST FLUSH. */
	for (int x=0; x < 4; x++) {
	  if (cards[x].getSuit() != cards[x+1].getSuit()) {
		flush = false;
	  }
	}

	/** SPRAWDZENIE, CZY JEST STRAIGHT. */
    for (int x = 1; x < 10; x++) {
      if (ranks[x] == 1 && ranks[x+1] == 1 && ranks[x+2] == 1 && ranks[x+3] == 1 && ranks[x+4] == 1) {
        straight = true;
        topStraightValue = x + 4; 
        break;
      }
    }
    /** SYTUACJA WYJATKOWA, "STRAIGHT" OD 10 W GORE. */
	if (ranks[10] == 1 && ranks[11] == 1 && ranks[12] == 1 && ranks[13] == 1 && ranks[1] == 1) {
	  straight = true;
	  topStraightValue = 14; 
	}

	/** PETLA PO KOLEJNYCH MIEJSCACH TABLICY ranks (OZNACZAJACYCH ILE TRZYMAMY W RECE KART O DANEJ WARTOSCI).
	 * JESLI TRAFIMY NA 2,3 LUB 4 (CZYLI TRZYMAMY W RECE 2,3 LUB 4 KARTY TEJ SAMEJ WARTOSCI), ILOSC TYCH KART
	 * ZAPISUJEMY POD ZMIENNA sameCards LUB sameCards2 (JESLI TA PIERWSZA JEST JUZ ZAJETA PRZEZ JAKAS PARE, TROJKE LUB CZWORKE),
	 * Z KOLEI ICH WARTOSC POD ZMIENNA smallGroupRank LUB largeGroupRank (ZALEZNIE OD TEGO, KTORA Z TYCH GRUP KART JEST WIEKSZA). */
	for(int x = 13; x > 0; x--) {
	  if (ranks[x] > sameCards) {
	    if (sameCards != 1) { sameCards2 = sameCards; smallGroupRank = largeGroupRank; }
		sameCards = ranks [x];
		if (x == 1) { largeGroupRank = 14; }
		else { largeGroupRank = x; }
      }
	  else if (ranks[x] > sameCards2) {
	    sameCards2 = ranks[x];
	    if(x == 1) { smallGroupRank = 14; }
	    else { smallGroupRank = x; }
	  }
    }

    /** UZYSKUJEMY PORZADEK KOLEJNYCH "HIGHEST CARDS" (POJEDYNCZYCH KART DODATKOWYCH,
	 * NIE MAJACYCH ZNACZENIA DLA WYNIKU) W CELU ROZSTRZYGANIA EWENTUALNYCH REMISOW
	 * ASY SPRAWDZAMY NA POCZATKU, PRZYPISUJEMY IM NAJWYZSZA WARTOSC. */
	if (ranks[1] == 1) {  
	  orderedRanks[index] = 14;
	  index++;
	}
	for (int x = 13; x > 1;x--){
	  if (ranks[x]==1){
	    orderedRanks[index] = x;
	    index++;
	  }
	}
	for (int x = 0; x < 6; x++){ value[x] = 0; }
	
	/** EWALUACJA TRZYMANYCH KART.
	* WARTOSCI TABLICY value TO KOLEJNE CZYNNIKI DECYDUJACE O TYM,
	* KTORY Z DWOCH POROWNYWANYCH WYNIKOW JEST WIEKSZY. */

    /** HIGH CARD */
	if (sameCards == 1) { 
	  value[0]=  1;
      value[1] = orderedRanks[0];
	  value[2] = orderedRanks[1];
	  value[3] = orderedRanks[2];
	  value[4] = orderedRanks[3];
	  value[5] = orderedRanks[4];
	}

	/** PAIR */
	if (sameCards == 2 && sameCards2 == 1) {
	  value[0] = 2;
      value[1] = largeGroupRank;
      value[2] = orderedRanks[0];
      value[3] = orderedRanks[1];
      value[4] = orderedRanks[2];
	}

	/** TWO PAIR'S */
    if (sameCards == 2 && sameCards2 == 2) {
	  value[0] = 3;
      value[1] = largeGroupRank > smallGroupRank ? largeGroupRank : smallGroupRank;
      value[2] = largeGroupRank < smallGroupRank ? largeGroupRank : smallGroupRank;
      value[3] = orderedRanks[0];
    }

    /** THREE OF A KIND */
    if (sameCards == 3 && sameCards2 != 2) {
      value[0] = 4;
      value[1] = largeGroupRank;
      value[2] = orderedRanks[0];
      value[3] = orderedRanks[1];
    }

    /** STRAIGHT */
    if (straight && !flush) {
      value[0] = 5;
      value[1] = topStraightValue;
    }

    /** FLUSH */
    if (flush && !straight) {
      value[0] = 6;
      value[1] = orderedRanks[0];
      value[2] = orderedRanks[1];
      value[3] = orderedRanks[2];
      value[4] = orderedRanks[3];
      value[5] = orderedRanks[4];
    }

    /** FULL HOUSE */
    if (sameCards == 3 && sameCards2 == 2) {
	  value[0] = 7;
      value[1] = largeGroupRank;
      value[2] = smallGroupRank;
    }

    /** FOUR OF A KIND */
    if (sameCards == 4) {
      value[0] = 8;
      value[1] = largeGroupRank;
      value[2] = orderedRanks[0];
    }

    /** POKER */	
    if (straight && flush) { 
      value[0] = 9;
      value[1] = topStraightValue;
    }
  }

  void printEvaluate() {
    String s;
    /** DRUKOWANIE WYNIKU */
	switch(value[0]){
	  case 1:
		s = "high card (" + Card.rankAsString(value[1]) + ")";
		break;
      case 2:
    	s = "one pair (" + Card.rankAsString(value[1]) + ")";
		break;
	  case 3:
		s = "two pairs (" + Card.rankAsString(value[1]) + ", " + Card.rankAsString(value[2]) + ")";
		break;
	  case 4:
		s = "three of a kind (" + Card.rankAsString(value[1]) + ")";
		break;
	  case 5:
		s = "straight (" + Card.rankAsString(value[1]) + " high)";
		break;
	  case 6:
		s = "flush";
		break;
	  case 7:
		s = "full house (" + Card.rankAsString(value[1]) + " over " + Card.rankAsString(value[2]) + ")";
	    break;
	  case 8:
		s = "four of a kind (" + Card.rankAsString(value[1]) + ")";
		break;
      case 9:
    	s = "straight flush (" + Card.rankAsString(value[1]) + " high)";
		break;
      default:
        s = "ERROR: invalid value!";
    }
	System.out.print(s);
  }
}

